package com.ayf.payment.game.api.wx;


import com.alibaba.fastjson.JSON;
import com.ayf.payment.game.api.cache.redis.RedisCacheUtil;
import com.ayf.payment.game.api.dto.ConfirmLoginDTO;
import com.ayf.payment.game.api.dto.MerchantDTO;
import com.ayf.payment.game.api.dto.QrToken;
import com.ayf.payment.game.api.dto.Token;
import com.ayf.payment.game.api.entity.platform.WxConfig;
import com.ayf.payment.game.api.entity.platform.WxUser;
import com.ayf.payment.game.api.exception.ParameterException;
import com.ayf.payment.game.api.service.TokenService;
import com.ayf.payment.game.api.service.platform.WxConfigService;
import com.ayf.payment.game.api.service.platform.WxPushMessageService;
import com.ayf.payment.game.api.service.platform.WxUserService;
import com.ayf.payment.game.api.type.CommonConstants;
import com.ayf.payment.game.api.type.LoginType;
import com.ayf.payment.game.api.utils.CommonResult;
import com.ayf.payment.game.api.utils.DateUtils;
import com.ayf.payment.game.api.utils.IPUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import org.apache.commons.lang.StringUtils;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 微信控制层
 * @Author: zh-liang
 */
@RestController
@RequestMapping("/wx")
public class WxController {

    @Autowired
    private WxConfigService wxConfigService;
    @Autowired
    private WxUserService wxUserService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private WxPushMessageService wxPushMessageService;
    @Autowired
    private RedisCacheUtil redisCacheUtil;
    @Autowired
    private MyConstant myConstant;

    /**
     * 用于验证消息的确来自微信服务器
     *
     * @param checkWeChat 微信验证实体类
     * @return String 原样返回随机字符串
     */
    @GetMapping("index")
    public String index(CheckWeChat checkWeChat, HttpServletRequest request) {
        LogPortal.info("验证消息的确来自微信服务器-request参数[{}]", JSON.toJSONString(request.getParameterMap()));
        checkWeChat.setTimestamp(request.getParameter("timestamp"));
        checkWeChat.setEchostr(request.getParameter("echostr"));
        checkWeChat.setNonce(request.getParameter("nonce"));
        checkWeChat.setSignature(request.getParameter("signature"));
        LogPortal.info("验证消息的确来自微信服务器-checkWeChat参数[{}]", JSON.toJSONString(checkWeChat));
        WxConfig config = wxConfigService.getConfig();
        //校验微信加密签名signature
        if (checkWeChat.checkSignature(config)) {
            return checkWeChat.getEchostr();
        }
        return "验证失败";
    }

    /**
     * 消息管理
     *
     * @param request 请求
     * @return String 类型的xml字符串
     */
    @PostMapping("index")
    public String msgIndex(HttpServletRequest request) {
        String xml = "";
        try {
            //获取根元素
            Element root = new SAXBuilder().build(request.getInputStream()).getRootElement();
            //执行消息处理
            xml = wxPushMessageService.messageHandle(root);
        } catch (JDOMException | IOException e) {
            e.printStackTrace();
        }
        return xml;
    }

    /**
     * 通过网页授权拉取用户登录信息
     *
     * @param code 获取网页授权的access_toke的凭证
     * @return
     */
    @GetMapping(value = "/code")
    public CommonResult<Map<String, Object>> code(@RequestParam("code") String code) {
        if (StringUtils.isEmpty(code)) {
            throw new ParameterException("code不能为空");
        }
        WxConfig config = wxConfigService.getConfig();
        String openid = myConstant.getOpenidByCode(code, config);
        WxUser dbWxUser = wxUserService.getWxUserByOpenid(openid);
        if (dbWxUser == null || dbWxUser.getMerchantId() == null) {
            return new CommonResult<>(601, "请先将账号与微信公众号绑定");
        } else {
            String type = "";
            if (dbWxUser.getType() == 1) {
                type = LoginType.FATHER.name();
            } else if (dbWxUser.getType() == 2) {
                type = LoginType.SON.name();
            } else if (dbWxUser.getType() == 3) {
                type = LoginType.TUI_G.name();
            }
            Token token = tokenService.createToken(dbWxUser.getMerchantId(), dbWxUser.getLoginId(), type);
            Map<String, Object> result = new HashMap<>(2);
            result.put("accessToken", token.getAccessToken());
            result.put("merchantId", dbWxUser.getMerchantId());
            return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "通过网页授权拉取用户登录accessToken成功", result);
        }
    }

    /**
     * 通过网页授权拉取用户登录信息
     *
     * @param code 获取网页授权的access_toke的凭证
     * @return
     */
    @GetMapping(value = "/getLoginInfo")
    public CommonResult<Map<String, Object>> getLoginInfo(@RequestParam("code") String code,
                                                          @RequestParam("key") String key, HttpServletRequest request) {
        if (StringUtils.isEmpty(code)) {
            throw new ParameterException("code不能为空");
        }
        if (StringUtils.isEmpty(key)) {
            throw new ParameterException("key不能为空");
        }
        WxConfig config = wxConfigService.getConfig();
        String openid = myConstant.getOpenidByCode(code, config);
        WxUser dbWxUser = wxUserService.getWxUserByOpenid(openid);
        if (dbWxUser == null) {
            WxUser wxUser = new WxUser();
            wxUser.setOpenid(openid);
            wxUser.setSubscribe(0);
            wxUserService.addWxUser(wxUser);
        }
        QrToken qrToken = new QrToken();
        if (dbWxUser == null || dbWxUser.getType() == null || dbWxUser.getMerchantId() == null || dbWxUser.getLoginId()
                == null) {
            qrToken.setStatus(0);
            qrToken.setOpenid(openid);
            redisCacheUtil.setObjectToCache("QR-CODE-LOGIN-TOKEN:" + key, qrToken, 300L, TimeUnit.SECONDS);
            return new CommonResult<>(198, "请先在PC端完成账号绑定");
        } else {
            qrToken.setStatus(1);
            if (dbWxUser.getType() == 1) {
                qrToken.setLoginId(dbWxUser.getMerchantId());
                qrToken.setLoginType("FATHER");
            } else if (dbWxUser.getType() == 2) {
                qrToken.setLoginId(dbWxUser.getLoginId());
                qrToken.setLoginType("SON");
            } else {
                qrToken.setLoginId(dbWxUser.getLoginId());
                qrToken.setLoginType("TuiG");
            }
            qrToken.setWxName(dbWxUser.getNickname());
            qrToken.setMerchantId(dbWxUser.getMerchantId());
            redisCacheUtil.setObjectToCache("QR-CODE-LOGIN-TOKEN:" + key, qrToken, 300L, TimeUnit.SECONDS);
            String account = wxUserService.getAccount(dbWxUser.getLoginId(), dbWxUser.getType());
            Map<String, Object> result = new HashMap<>(3);
            result.put("account", account);
            result.put("date", DateUtils.dateToString(new Date()));
            result.put("ip", IPUtils.getIp(request));
            return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "通过网页授权拉取用户登录信息成功", result);
        }
    }

    /**
     * 确认登录
     *
     * @param dto
     * @return
     */
    @PostMapping(value = "/confirmLogin")
    public CommonResult<Map<String, Object>> confirmLogin(@RequestBody ConfirmLoginDTO dto) {
        if (dto.getStatus() == null) {
            throw new ParameterException("状态不能为空");
        }
        QrToken qrToken = redisCacheUtil.getObjectFromCache("QR-CODE-LOGIN-TOKEN:" + dto.getKey());
        if (qrToken == null) {
            return new CommonResult<>(-1, "非法操作");
        } else {
            if (dto.getStatus() == 0) {
                qrToken.setStatus(2);
                redisCacheUtil.setObjectToCache("QR-CODE-LOGIN-TOKEN:" + dto.getKey(), qrToken, 300L, TimeUnit.SECONDS);
                return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "取消成功");
            }
            qrToken.setStatus(3);
            redisCacheUtil.setObjectToCache("QR-CODE-LOGIN-TOKEN:" + dto.getKey(), qrToken, 300L, TimeUnit.SECONDS);
            return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "登录成功");
        }
    }

    /**
     * 拉取用户解绑信息
     *
     * @param code 获取网页授权的access_toke的凭证
     * @return
     */
    @GetMapping(value = "/getUnBindInfo")
    public CommonResult<Map<String, Object>> getUnBindInfo(@RequestParam("code") String code,
                                                           @RequestParam("key") String key, HttpServletRequest request) {
        if (StringUtils.isEmpty(code)) {
            throw new ParameterException("code不能为空");
        }
        if (StringUtils.isEmpty(key)) {
            throw new ParameterException("key不能为空");
        }
        MerchantDTO merchantDTO = redisCacheUtil.getObjectFromCache("WX_UN_BIND:" + key);
        if (merchantDTO == null) {
            return new CommonResult<>(181, "二维码已失效，请扫描新的二维码");
        }
        WxUser bindWxUser = wxUserService.getBindWxUser(merchantDTO.getId(), merchantDTO.getLoginId());
        WxConfig config = wxConfigService.getConfig();
        String openid = myConstant.getOpenidByCode(code, config);
        WxUser dbWxUser = wxUserService.getWxUserByOpenid(openid);
        if (dbWxUser == null || !openid.equals(bindWxUser.getOpenid())) {
            return new CommonResult<>(182, "请使用微信【" + bindWxUser.getNickname() + "】扫描二维码进行解绑");
        }
        redisCacheUtil.setObjectToCache("WX_UN_BIND_STATUS:" + key, 1, 300L, TimeUnit.SECONDS);
        String account = wxUserService.getAccount(dbWxUser.getLoginId(), dbWxUser.getType());
        Map<String, Object> result = new HashMap<>(3);
        result.put("account", account);
        result.put("date", DateUtils.dateToString(new Date()));
        result.put("ip", IPUtils.getIp(request));
        return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "通过网页授权拉取用户解绑信息成功", result);
    }

    /**
     * 确认解绑
     *
     * @param dto
     * @return
     */
    @PostMapping(value = "/confirmUnBind")
    public CommonResult<Map<String, Object>> confirmUnBind(@RequestBody ConfirmLoginDTO dto) {
        if (StringUtils.isEmpty(dto.getKey())) {
            throw new ParameterException("key不能为空");
        }
        if (dto.getStatus() == null) {
            throw new ParameterException("状态不能为空");
        }
        MerchantDTO merchantDTO = redisCacheUtil.getObjectFromCache("WX_UN_BIND:" + dto.getKey());
        if (merchantDTO == null) {
            return new CommonResult<>(181, "等待时间过长，已失效，请扫描新的二维码");
        }
        if (dto.getStatus() == 0) {
            redisCacheUtil.setObjectToCache("WX_UN_BIND_STATUS:" + dto.getKey(), 2, 300L, TimeUnit.SECONDS);
            return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "取消成功");
        }
        redisCacheUtil.setObjectToCache("WX_UN_BIND_STATUS:" + dto.getKey(), 3, 300L, TimeUnit.SECONDS);
        wxUserService.unBindWx(merchantDTO.getId(), merchantDTO.getLoginId());
        return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "解绑成功");
    }

    /**
     * 获取微信公众号状态
     *
     * @return
     */
    @GetMapping(value = "/getStatus")
    public CommonResult<Integer> getStatus() {
        WxConfig config = wxConfigService.getConfig();
        return new CommonResult<>(CommonConstants.RETURN_SUCCESS, "获取微信公众号状态成功", config.getStatus());
    }
}
